package com.ssy.lingxi.pay.callback;


import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.ssy.lingxi.common.constant.order.OrderPaymentParameterEnum;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.order.api.feign.OrderFeignService;
import com.ssy.lingxi.order.api.model.vo.request.OrderPayCallbackFeignVO;
import com.ssy.lingxi.pay.api.common.ServiceTypeEnum;
import com.ssy.lingxi.pay.model.assetAccount.AttachInfo;
import com.ssy.lingxi.pay.model.dto.ParameterCacheDTO;
import com.ssy.lingxi.pay.service.ICreditService;
import com.ssy.lingxi.pay.service.INotifyRecordService;
import com.ssy.lingxi.pay.service.IPayCacheService;
import com.ssy.lingxi.pay.service.assetAccount.IMemberAssetAccountService;
import com.ssy.lingxi.pay.utils.WeChatPayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 微信回调统一入口
 * jw.chen
 */
@RestController
@RequestMapping("/pay/wechat")
public class WeChatController {

    private static final Logger logger = LoggerFactory.getLogger(WeChatController.class);

    @Resource
    private INotifyRecordService notifyRecordService;

    @Resource
    private IPayCacheService payCacheService;

    @Resource
    private IMemberAssetAccountService memberAssetAccountService;

    @Resource
    private OrderFeignService orderFeignService;

    @Resource
    private ICreditService creditService;

    /**
     * 支付通知接口
     * 1. 首先记录微信流水
     * 2. 进行业务操作
     */
    @RequestMapping(value = "/notify", method = RequestMethod.POST)
    @ResponseBody
    public String notify(HttpServletRequest request, HttpServletResponse response) {
        logger.info("------------微信支付回调通知--------------");
        //读取参数
        StringBuffer xmlData = new StringBuffer();
        try {
            InputStream inputStream = request.getInputStream();
            String line;
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
            while ((line = bufferedReader.readLine()) != null) {
                xmlData.append(line);
            }
            bufferedReader.close();
            inputStream.close();

            logger.info("通知内容xml====={}", xmlData.toString());
            //解析附加信息
            String attachStr = WeChatPayUtil.getXmlByKey(xmlData.toString(), "attach");
            AttachInfo attachInfo = payCacheService.deserializeObject(attachStr, AttachInfo.class);
            Integer payType = attachInfo.getPayType();              //支付方式
            Long memberId = attachInfo.getMemberId();               //会员id
            Long memberRoleId = attachInfo.getMemberRoleId();       //会员角色id
            String serviceType = attachInfo.getServiceType();       //服务类型p
            String attach = attachInfo.getAttach();                 //附加信息
            String nonce = attachInfo.getNonce();                   //用于缓存的随机字符串


            //从缓存中获取支付参数
            List<ParameterCacheDTO> parameters = payCacheService.findPayParameters(memberId, memberRoleId, payType, nonce);
            WxPayConfig payConfig = new WxPayConfig();
            parameters.forEach(p -> {
                if(p.getCode().equals(OrderPaymentParameterEnum.WECHAT_MERCHANT_ID.getCode())) {
                    payConfig.setMchId(p.getValue());
                } else if (p.getCode().equals(OrderPaymentParameterEnum.WECHAT_APP_ID.getCode())) {
                    payConfig.setAppId(p.getValue());
                } else if (p.getCode().equals(OrderPaymentParameterEnum.WECHAT_API_KEY.getCode())) {
                    payConfig.setMchKey(p.getValue());
                } else {
                    logger.error("微信支付读取缓存数据错误：code => " + p.getCode() + " , value => " + p.getValue());
                }
            });

            //实例化WxPayService
            WxPayService wxPayService = new WxPayServiceImpl();
            wxPayService.setConfig(payConfig);
            WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData.toString());
            //判断返回结果是否为空
            if (notifyResult != null) {
                //商户订单号
                String out_trade_no = notifyResult.getOutTradeNo();
                //微信交易号
                String trade_no = notifyResult.getTransactionId();
                //新增交易记录
                notifyRecordService.saveWeChatNotifyRecord(notifyResult);
                //判断返回结果是否成功
                if (notifyResult.getReturnCode().equals(WeChatPayUtil.SUCCESS)) {
                    //判断是否支付成功
                    if (notifyResult.getResultCode().equals(WeChatPayUtil.SUCCESS)) {
                        //回调业务方法
                        if (ServiceTypeEnum.Pay_Recharge.getCode().equals(serviceType)) {
                            memberAssetAccountService.payNotify(out_trade_no, trade_no);
                            logger.info(ServiceTypeEnum.Pay_Recharge.getMessage() + ":==========订单号：" + out_trade_no + "通知成功");
                        } else if (ServiceTypeEnum.Pay_Credit.getCode().equals(serviceType)) {
                            creditService.confirmRepaySucceed(out_trade_no, trade_no);
                            logger.info(ServiceTypeEnum.Pay_Credit.getMessage() + ":==========订单号：" + out_trade_no + "通知成功");
                        } else if (ServiceTypeEnum.Order_Pay.getCode().equals(serviceType)) {
                            OrderPayCallbackFeignVO orderPayCallbackFeignVO = new OrderPayCallbackFeignVO();
                            orderPayCallbackFeignVO.setTradeNo(out_trade_no);
                            orderPayCallbackFeignVO.setAttach(attach);
                            orderPayCallbackFeignVO.setPaySuccess(true);
                            Wrapper<Void> orderCallbackResult = orderFeignService.orderPayCallback(orderPayCallbackFeignVO);
                            logger.info(ServiceTypeEnum.Order_Pay.getMessage() + ":==========订单号：" + out_trade_no + " attach：" + attach + " , 支付成功通知结果" + orderCallbackResult.getMessage());
                        } else {
                            logger.error("==========订单号：" + out_trade_no + "通知失败，未找到对应的服务");
                        }
                        return WeChatPayUtil.returnWeChatNotify(response, true);
                    } else {
                        if (ServiceTypeEnum.Order_Pay.getCode().equals(serviceType)) {
                            OrderPayCallbackFeignVO orderPayCallbackFeignVO = new OrderPayCallbackFeignVO();
                            orderPayCallbackFeignVO.setTradeNo(out_trade_no);
                            orderPayCallbackFeignVO.setAttach(attach);
                            orderPayCallbackFeignVO.setPaySuccess(false);
                            Wrapper<Void> orderCallbackResult = orderFeignService.orderPayCallback(orderPayCallbackFeignVO);
                            logger.info(ServiceTypeEnum.Order_Pay.getMessage() + ":==========订单号：" + out_trade_no + " attach：" + attach + " , 支付失败通知结果" + orderCallbackResult.getMessage());
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("微信支付回调通知==error={}", e.getMessage());
            e.printStackTrace();
        }
        return WeChatPayUtil.returnWeChatNotify(response, false);
    }

}
